package com.koron.common.core.business.configsettings.service;

import com.koron.bean.base.Response;
import com.koron.bean.util.RedisUtils;
import com.koron.common.core.business.configsettings.bean.ConfigDetail;
import com.koron.common.core.business.configsettings.bean.ConfigDetailQuery;
import com.koron.common.core.business.configsettings.bean.ConfigType;
import com.koron.common.core.business.configsettings.mapper.ConfigDetailMapper;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.UpdateRedis;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 系统管理-配置详情{@code ConfigDetail}服务实现类
 *
 * <p>方法1-checkBeforeInsert：新增单条数据</p>
 * <p>方法2-checkBeforeDelete：逻辑删除单条数据</p>
 * <p>方法3-checkBeforeUpdate：更新单条数据</p>
 * <p>方法4-getList：根据条件查询数据</p>
 * <p>方法5-getByClassifyCodeAndCodeAndAppidAndKey：根据classifyCode,code,appid,key 查询单条配置项详情</p>
 * <p>方法6-getListByConfigId：根据configId，查询对应的配置详情</p>
 * <p>方法7-getRedisKeyByConfigDetail：根据configDetail获取redisKey</p>
 *
 * @author 朱超
 * @since 2021-09-01
 */
@Service
public class ConfigDetailService {

    @Autowired
    private UpdateRedis updateRedis;

    @Autowired
    private ConfigTypeService configTypeService;

    private static final String KEY_PREFIX = "eam:configSettings:";


    /**
     * 新增单条数据
     *
     * @param factory
     * @param configDetail:至少包含configId,appid,key,value
     * @return Response对象
     * @throws {@code Internal Server Error} 同一配置项的同一租户下key不能重复
     * @throws {@code Internal Server Error} 同一配置项的同一租户下value不能重复
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("checkBeforeInsert")
    public Response checkBeforeInsert(SessionFactory factory, ConfigDetail configDetail) {
        ConfigDetailMapper configDetailMapper = factory.getMapper(ConfigDetailMapper.class);
        String configId = configDetail.getConfigId();
        String appid = configDetail.getAppid();
        String key = configDetail.getKey();

        // 1. 判断同一配置项，同一租户下的key是否重复
        ConfigDetailQuery uniqueConfigQuery = new ConfigDetailQuery();
        uniqueConfigQuery.setConfigId(configId);
        uniqueConfigQuery.setAppid(appid);
        uniqueConfigQuery.setKey(key);
        ConfigDetail uniqueConfigKey = configDetailMapper.getSingle(uniqueConfigQuery);
        if (uniqueConfigKey != null) {
            return Response.fail("同一配置项的同一租户下key不能重复");
        }
        // 2. 设置id
        configDetail.setId(CodeTools.getCode32());
        // 3. 设置delete_flag
        configDetail.setDeleteFlag(0);
        // 4. 新增数据
        configDetailMapper.insert(configDetail);
        // 5. redis添加数据
        updateRedis.setConfigDetailInRedis(factory, configDetail);
        // 6. redis更新配置
        ConfigType configType = configTypeService.getById(factory, configId);
        List<ConfigDetail> configDetailList = this.getListByConfigId(factory, configId);
        configType.setConfigDetailList(configDetailList);
        updateRedis.setConfigTypeInRedis(configType);

        return Response.success("新增成功");
    }

    /**
     * 逻辑删除单条数据
     *
     * @param factory
     * @param id
     * @return Response
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("checkBeforeDelete")
    public Response checkBeforeDelete(SessionFactory factory, String id) {
        ConfigDetailMapper configDetailMapper = factory.getMapper(ConfigDetailMapper.class);

        // 1. 根据id查出对应的数据
        ConfigDetailQuery configDetailQuery = new ConfigDetailQuery();
        configDetailQuery.setId(id);
        ConfigDetail configDetail = configDetailMapper.getSingle(configDetailQuery);
        String configId = configDetail.getConfigId();
        // 2. 获取redisKey
        String redisKey = getRedisKeyByConfigDetail(factory, configDetail);
        // 4. 逻辑删除单条数据
        configDetail.setDeleteFlag(1);
        configDetailMapper.update(configDetail);
        // 5. redis删除
        RedisUtils.delete(redisKey);
        // 6. redis更新配置
        ConfigType configType = configTypeService.getById(factory, configId);
        List<ConfigDetail> configDetailList = this.getListByConfigId(factory, configId);
        configType.setConfigDetailList(configDetailList);
        updateRedis.setConfigTypeInRedis(configType);

        return Response.success("删除成功");
    }

    /**
     * 更新单条数据
     *
     * @param factory
     * @param configDetail: 至少包含：configId，appid，key，value，id
     * @return Response
     * @throws {@code Internal Server Error} 同一配置项的同一租户下key不能重复
     * @throws {@code Internal Server Error} 同一配置项的同一租户下value不能重复
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("checkBeforeUpdate")
    public Response checkBeforeUpdate(SessionFactory factory, ConfigDetail configDetail) {
        ConfigDetailMapper configDetailMapper = factory.getMapper(ConfigDetailMapper.class);
        String configId = configDetail.getConfigId();
        String appid = configDetail.getAppid();
        String key = configDetail.getKey();
        String id = configDetail.getId();

        // 1. 判断同一配置项，同一租户下的key是否重复
        ConfigDetailQuery uniqueConfigQuery = new ConfigDetailQuery();
        uniqueConfigQuery.setConfigId(configId);
        uniqueConfigQuery.setAppid(appid);
        uniqueConfigQuery.setKey(key);
        ConfigDetail uniqueConfigKey = configDetailMapper.getSingle(uniqueConfigQuery);
        if (uniqueConfigKey != null && !uniqueConfigKey.getId().equals(id)) {
            return Response.fail("同一配置项的同一租户下key不能重复");
        }
        // 2. 通过id获取未更新的数据
        ConfigDetailQuery queryFormer = new ConfigDetailQuery();
        queryFormer.setId(id);
        ConfigDetail formerConfigDetail = configDetailMapper.getSingle(queryFormer);
        String formerKey = formerConfigDetail.getKey();
        // 3 只有当key变更的时候，redisKey才会变更
        if (!formerKey.equals(key)) {
            // 3.1 获取原来的redisKey，并删除
            String formerRedisKey = getRedisKeyByConfigDetail(factory, formerConfigDetail);
            RedisUtils.delete(formerRedisKey);
        }
        // 4. 更新数据
        configDetailMapper.update(configDetail);
        // 5. 更新redis
        updateRedis.setConfigDetailInRedis(factory, configDetail);
        // 7. redis更新配置
        ConfigType configType = configTypeService.getById(factory, configId);
        List<ConfigDetail> configDetailList = this.getListByConfigId(factory, configId);
        configType.setConfigDetailList(configDetailList);
        updateRedis.setConfigTypeInRedis(configType);

        return Response.success("更新成功");
    }

    /**
     * 根据条件查询数据
     *
     * @param factory
     * @param configId
     * @param appid
     * @return Response
     * @version 1.0
     * @see Response
     */
    @TaskAnnotation("getList")
    public Response getList(SessionFactory factory, String configId, String appid) {
        ConfigDetailMapper configDetailMapper = factory.getMapper(ConfigDetailMapper.class);
        ConfigDetailQuery configDetailQuery = new ConfigDetailQuery();

        // 1. 构造请求实例
        configDetailQuery.setConfigId(configId);
        configDetailQuery.setAppid(appid);
        // 2. 查出数据
        List<ConfigDetail> configDetailList = configDetailMapper.getList(configDetailQuery);

        return Response.success(configDetailList);
    }

    /**
     * 根据classifyCode,code,appid,key 查询单条配置项详情
     *
     * @param factory
     * @param classifyCode
     * @param code
     * @param appid
     * @param key
     * @return ConfigDetail
     * @version 1.0
     * @see ConfigDetail
     */
    @TaskAnnotation("getByClassifyCodeAndCodeAndAppidAndKey")
    public ConfigDetail getByClassifyCodeAndCodeAndAppidAndKey(SessionFactory factory, String classifyCode, String code, String appid, String key) {
        ConfigDetailMapper configDetailMapper = factory.getMapper(ConfigDetailMapper.class);
        ConfigDetail configDetail = new ConfigDetail();

        // 1. 定义redisKey
        String redisKey = KEY_PREFIX + classifyCode + ":" + code + ":" + appid + ":" + key;
        // 2. 尝试从redis中获取
        Map<Object, Object> redisValue = RedisUtils.hmget(redisKey);
        if (redisValue.size() != 0) {
            // 3. 将redis中获取的数据赋值到实例中
            configDetail.setId((String) redisValue.get("id"));
            configDetail.setConfigId((String) redisValue.get("configId"));
            configDetail.setAppid((String) redisValue.get("appid"));
            configDetail.setKey((String) redisValue.get("key"));
            configDetail.setValue((String) redisValue.get("value"));
            configDetail.setDescription((String) redisValue.get("description"));
        } else {
            // 4. 如果redis中没有，则从数据库获取
            // 4.1 通过classifyCode和code查询configType，获取id
            ConfigType configType = configTypeService.getByClassifyCodeAndCode(factory, classifyCode, code);
            String configId = configType.getId();
            // 4.2 通过configId,appid,key查询configDetail
            ConfigDetailQuery configDetailQuery = new ConfigDetailQuery();
            configDetailQuery.setConfigId(configId);
            configDetailQuery.setAppid(appid);
            configDetailQuery.setKey(key);
            configDetail = configDetailMapper.getSingle(configDetailQuery);
            // 5. 更新redis
            Map<String, Object> configDetailValue = new HashMap<>();
            configDetailValue.put("id", configDetail.getId());
            configDetailValue.put("configId", configId);
            configDetailValue.put("appid", appid);
            configDetailValue.put("key", key);
            configDetailValue.put("value", configDetail.getValue());
            configDetailValue.put("description", configDetail.getDescription());
            RedisUtils.hmset(redisKey, configDetailValue);
        }

        return configDetail;
    }

    /**
     * 根据configId，查询对应的配置详情
     *
     * @param factory
     * @param configId
     * @return List<ConfigDetail>
     * @version 1.0
     * @see ConfigDetail
     */
    public List<ConfigDetail> getListByConfigId(SessionFactory factory, String configId) {
        ConfigDetailMapper configDetailMapper = factory.getMapper(ConfigDetailMapper.class);
        ConfigDetailQuery configDetailQuery = new ConfigDetailQuery();

        // 1. 根据configId查出对应的数据
        configDetailQuery.setConfigId(configId);
        return configDetailMapper.getList(configDetailQuery);
    }

    /**
     * 根据configDetail获取redisKey
     *
     * @param factory
     * @param configDetail
     * @return redisKey
     * @version 1.0
     * @see ConfigDetail
     */
    public String getRedisKeyByConfigDetail(SessionFactory factory, ConfigDetail configDetail) {
        String configId = configDetail.getConfigId();
        String appid = configDetail.getAppid();
        String key = configDetail.getKey();

        // 1. 根据configId查出classifyCode和code
        ConfigType configType = configTypeService.getById(factory, configId);
        String classifyCode = configType.getClassifyCode();
        String code = configType.getCode();
        // 2. 构造redisKey
        return KEY_PREFIX + classifyCode + ":" + code + ":" + appid + ":" + key;
    }
}
